grammar LocScript;

options {
	output=AST;
	//ASTLabelType=LocScriptAST;
}

tokens {
OPEN_PARENS='(';
CLOSE_PARENS=')';
OPEN_BRACK='[';
CLOSE_BRACK=']';
OPEN_BRACE='{';
CLOSE_BRACE='}';
ASSIGN='=';
PLUS_ASSIGN='+=';
MINUS_ASSIGN='-=';
MULT_ASSIGN='*=';
DIV_ASSIGN='/=';
OR='||';
AND='&&';
BIT_OR='|';
BIT_AND='&';
XOR='^';
EQUALS='==';
NOT_EQUALS='!=';
GREATER_THAN='>';
LESS_THAN='<';
GREATER_THAN_EQUALS='>=';
LESS_THAN_EQUALS='<=';
SHIFT_LEFT='<<';
SHIFT_RIGHT='>>';
U_SHIFT_RIGHT='>>>';
PLUS='+';
MINUS='-';
MULT='*';
DIV='/';
MOD='%';
NOT='!';
BIT_NEG='~';
TRUE='true';
FALSE='false';
RETURN='>:';
MEM_ACCESS='.';
VAR='$';
FOR='for';
THIS;
ARRAY_ACCESS;
DEF;
NEG;
POST_INC;
PRE_INC;
POST_DEC;
PRE_DEC;
EXPR;
COND_OP;
BLOCK;
FILTER;
}


@header {
	//package script.grammar;
}

ID  :	('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*
    ;

INT :	'0'..'9'+
    ;

FLOAT
    :   ('0'..'9')+ '.' ('0'..'9')*
    |   '.' ('0'..'9')+
    |   ('0'..'9')+
    ;

WS  :   ( ' '
        | '\t'
        | '\r'
        | '\n'
        ) {$channel=HIDDEN;}
    ;
    
start
	:	stat* EOF -> ^(FILTER stat*)
	;
	
block
	:	stat* -> ^(BLOCK stat*)
	;
	
foreach
	:	FOR OPEN_PARENS defCore ':' expr CLOSE_PARENS OPEN_BRACE block CLOSE_BRACE
		-> ^(FOR ^(DEF defCore) expr block)
	;
	
defList
	:	def (','! def)*
	;
	
def	:	defCore (ASSIGN expr)? -> ^(DEF defCore expr?)
	;
	
defCore
	:	VAR! ID OPEN_PARENS! ID CLOSE_PARENS!
	;
    
expr:	expr0 -> ^(EXPR expr0)
	;
	
expr0
	:	VAR ID (a=ASSIGN|a=PLUS_ASSIGN|a=MINUS_ASSIGN|a=MULT_ASSIGN|a=DIV_ASSIGN) expr0 -> ^($a ^(VAR ID) expr0)
	|	expr1
	;
	
expr1
options{backtrack=true;memoize=true;}
	:	expr2 '?' a=expr0 ':' b=expr0 -> ^(COND_OP expr2 $a $b)
	|	expr2
	;
	
expr2
	:	expr3 (OR^ expr3)*
	;
	
expr3
	:	expr4 (AND^ expr4)*
	;
	
expr4
	:	expr5 (BIT_OR^ expr5)*
	;
	
expr5
	:	expr6 (XOR^ expr6)*
	;
	
expr6
	:	expr7 (BIT_AND^ expr7)*
	;
	
expr7
	:	expr8 ((EQUALS|NOT_EQUALS)^ expr8)*
	;
	
expr8
	:	expr9 ((LESS_THAN|GREATER_THAN|LESS_THAN_EQUALS|GREATER_THAN_EQUALS)^ expr9)*
	;
	
expr9
	:	expr10 ((SHIFT_LEFT|SHIFT_RIGHT|U_SHIFT_RIGHT)^ expr10)*
	;
	
expr10
	:	expr11 ((PLUS|MINUS)^ expr11)*
	;
	
expr11
	:	expr12 ((MULT|DIV|MOD)^ expr12)*
	;
	
expr12
	:	MINUS expr12 -> ^(NEG expr12)
	|	BIT_NEG^ expr12
	|	'++' expr13 -> ^(PRE_INC expr13)
	|	'--' expr13 -> ^(PRE_DEC expr13)
	|	expr13
	;
	
expr13
options{backtrack=true;memoize=true;}
	:	(primary -> primary)
		(
		(MEM_ACCESS ID -> ^(MEM_ACCESS $expr13 ID)
		|OPEN_BRACK expr0 CLOSE_BRACK -> ^(ARRAY_ACCESS $expr13 expr0))
		)*
	|	primary '++' -> ^(POST_INC primary)
	|	primary '--' -> ^(POST_DEC primary)
	;
	
primary
	:	INT|FLOAT
	|	TRUE|FALSE
	|	VAR^ ID
	|	MEM_ACCESS ID -> ^(MEM_ACCESS THIS ID)
	|	OPEN_PARENS! expr0 CLOSE_PARENS!
	;
	
stat:	expr ';'!
	|	RETURN^ expr ';'!
	|	defList ';'!
	|	foreach
	;